local skynet        = require "skynet"
local service_class = require "service_class"
local server_config = dofile(skynet.getenv("server_config"))

local guid_mgr = class("guid_mgr",service_class)

function guid_mgr:ctor()
	self.mongo_pool = nil
    self.mongo_conf = nil
    self.redis_pool = nil
    guid_mgr.super.ctor(self)
end

function guid_mgr:reload()
    guid_mgr.super.reload(self)
end

function guid_mgr:open(conf)

    print("guid_mgr:open")
	self.mongo_conf = {
        host = server_config.mongo_account_conf.host,
        port = server_config.mongo_account_conf.port,
        username = server_config.mongo_account_conf.user,
        password = server_config.mongo_account_conf.password,
        db_name = server_config.mongo_account_conf.dbname,
        coll_name = server_config.mongo_account_conf.collname,
        incr_name = server_config.mongo_account_conf.incrname,   --自增长id
        authdb = assert(server_config.mongo_account_conf.dbname),
    }
    print_r(self.mongo_conf)
    self.mongo_pool = require("mongo_pool").new(self.mongo_conf)

    local redis_conf = {
        host = server_config.redis_conf.host,
        port = server_config.redis_conf.port,
        db = server_config.redis_conf.db,
        auth = server_config.redis_conf.auth,
    }
    print_r(redis_conf)
    self.redis_pool = require("redis_pool").new(redis_conf)

    --初始化IncrId
    -- self:init_incrid()
    return true
end

function guid_mgr:init_incrid()
    -- --读取mongo的自增长Id到Redis中
    -- local ok,ret
    -- local mongo_client = self.mongo_pool:get_conn_from_pool()
    -- ok,ret = xpcall(function()
    --     return mongo_client[self.mongo_conf.db_name][self.mongo_conf.incr_name]:findOne({})
    -- end,debug.traceback)
    -- local incr_id = 0

    -- if not ok then
    --      --查询mongoDB失败
    --     errlog("Read mongoDB incr_name fail!", ret)
    --     self.mongo_pool:putback_to_pool(mongo_client)        --清理mongo连接
    --     return
    -- end

    -- if not ret or not ret.incr_id then
    --     --读取失败
    --     errlog("IncrId not exist ! Try to insert incr_name Value 0...")
    --     --读取错误 尝试重新写入这个值
    --     local init_incr_info = {incr_id = 0}
    --     ok, ret = xpcall(function()
    --         return mongo_client[self.mongo_conf.db_name][self.mongo_conf.incr_name]:safe_update({}, {['$set'] = init_incr_info}, true)
    --     end, debug.traceback)
    --     if not ok or not ret then
    --         --写入incr_id失败
    --         errlog("Write mongo incr_name fail!", ret)
    --         self.mongo_pool:putback_to_pool(mongo_client)    --清理mongo连接
    --         return
    --     end
    --     --设置成功
    --     print("Write mongo incr_name success.")
    -- end
    -- incr_id = tonumber(ret.incr_id)
    --  --将自增长id放入Redis中
    -- local redis_client = self.redis_pool:get_conn_from_pool()
    -- redis_client:set(self:get_incr_key(), incr_id)
    -- self.redis_pool:putback_to_pool(redis_client)
    -- self.mongo_pool:putback_to_pool(mongo_client)

    -- if not ok then
    --     --查询mongoDB失败
    --     errlog("Read mongoDB incr_name fail!", ret)
    --     self.mongo_pool:putback_to_pool(mongo_client)        --清理mongo连接
    --     return
    -- elseif not ret or not ret.incr_id then
    --     --读取失败
    --     errlog("IncrId not exist ! Try to insert incr_name Value 0...")
    --     --读取错误 尝试重新写入这个值
    --     local init_incr_info = {incr_id = 0}
    --     local ok, ret = xpcall(function()
    --         return mongo_client[self.mongo_conf.db_name][self.mongo_conf.incr_name]:safe_update({}, {['$set'] = init_incr_info}, true)
    --     end, debug.traceback)
    --     if not ok or not ret then
    --         --写入incr_id失败
    --         errlog("Write mongo incr_name fail!", ret)
    --         self.mongo_pool:putback_to_pool(mongo_client)    --清理mongo连接
    --         return
    --     else
    --         --设置成功
    --         print("Write mongo incr_name success.")
    --     end
    -- else
    --     --读取成功
    --     incr_id = tonumber(ret.incr_id)
    -- end

    -- --将自增长id放入Redis中
    -- local redis_client = self.redis_pool:get_conn_from_pool()
    -- redis_client:set(self:get_incr_key(), incr_id)
    -- self.redis_pool:putback_to_pool(redis_client)
    -- self.mongo_pool:putback_to_pool(mongo_client)
    -- print("Read init_incrid OK! incr_id = ", incr_id)
end

function guid_mgr:select_from_mongodb_uid(uid)
    local client  = self.mongo_pool:get_conn_from_pool()
    local ok,ret = xpcall(function()
        return client[self.mongo_conf.db_name][self.mongo_conf.coll_name]:findOne({uid = uid})
    end,debug.traceback)
    self.mongo_pool:putback_to_pool(client)
    if not ok then
        errlog(uid,ret)
        return
    end

    return ret
end

function guid_mgr:select_from_mongodb_guid(guid)
    local client  = self.mongo_pool:get_conn_from_pool()
    local ok,ret = xpcall(function()
        return client[self.mongo_conf.db_name][self.mongo_conf.coll_name]:findOne({guid = guid})
    end,debug.traceback)
    self.mongo_pool:putback_to_pool(client)
    if not ok then
        errlog(uid,ret)
        return
    end

    return ret
end

local save_cache_script = [[
    redis.call('set',KEYS[1],ARGV[1])
    redis.call('set',KEYS[2],ARGV[2])
]]

function guid_mgr:save_data_to_cache(guid,uid,conn)
    local guid_key = self:make_guid_key(guid)
    local uid_key = self:make_uid_key(uid)
    print(guid_key,uid,uid_key,guid)
    conn:eval(save_cache_script,2,guid_key,uid_key,uid,guid)
end

local create_uid_script = [[
    local incr_id_key = KEYS[1]
    local guid = KEYS[2]
    local guid_key = KEYS[3]

    local new_id = redis.call('incr',incr_id_key)
    new_id = tonumber(new_id) + 100000

    redis.call('set',guid_key,new_id)

    local uid_key ='uid_' .. new_id
    redis.call('set',uid_key,guid)

    return new_id
]]

function guid_mgr:create_uid(guid,conn)
    local incr_id_key = self:get_incr_key()
    local guid_key = self:make_guid_key(guid)
    local uid = conn:eval(create_uid_script,3,incr_id_key,guid,guid_key)

    local user_info = {guid = guid,uid = tonumber(uid)}
    local client  = self.mongo_pool:get_conn_from_pool()
    local ok,ret = xpcall(function()
        return client[self.mongo_conf.db_name][self.mongo_conf.coll_name]:safe_update({_id = guid},{['$set'] = user_info},true)
    end,debug.traceback)
    -- local ok, ret = xpcall(function()
    --     return client[self.mongo_conf.db_name][self.mongo_conf.incr_name]:safe_update({}, {['$set'] = {incr_id = user_info.uid - 100000}}, true)
    -- end,debug.traceback)

    print("create_uid---------->",ok)
    if not ok then
        errlog(ret)
    end
    self.mongo_pool:putback_to_pool(client)
    -- print("guid_mgr->create_uid",uid)
    -- billlog({
    --     op="create_uid",
    --     curr_uid = uid
    -- })

    return uid
end


function guid_mgr:make_guid_key(guid)
    return 'guid_' .. guid
end

function guid_mgr:make_uid_key(uid)
    return 'uid_' .. uid
end

function guid_mgr:get_incr_key()
    return 'guid_incr_key'
end

function guid_mgr:get_uid(guid)
    if guid and type(guid) == 'number' then
        local conn = self.redis_pool:get_conn_from_pool()
        local incr_id_key = self:get_incr_key()
        local guid_key = self:make_guid_key(guid)
        local uid = conn:get(guid_key)
        if not uid then
            mongo_data = self:select_from_mongodb_guid(guid)
            if mongo_data then
                uid = mongo_data.uid
                self:save_data_to_cache(guid,uid,conn)
                print(guid,"----------- find data in  mongodb")
            else
                uid = self:create_uid(guid,conn)
                print(guid,"+++++++++++ need create uid")
                --self:save_data_to_cache(guid,uid,conn)
            end
        end
        self.redis_pool:putback_to_pool(conn)
        return tonumber(uid)
    end

    return false
end

local REGISTER_ROBOTS_LUA = [[
    local incr_id_key = KEYS[1]
    local register_num = KEYS[2]
    local uid_list = {}
    for i = 1,register_num do 
        local new_id = redis.call('incr',incr_id_key)
        new_id = tonumber(new_id) + 100000
        table.insert(uid_list,new_id)
    end

    return uid_list
]]

function guid_mgr:register_robots(num)
    if num and type(num) == 'number' then
        local conn = self.redis_pool:get_conn_from_pool()
        local incr_id_key = self:get_incr_key()
        local uid_list = conn:eval(REGISTER_ROBOTS_LUA,2,incr_id_key,num)
        self.redis_pool:putback_to_pool(conn)
        print("guid_mgr->create_uid",uid_list[#uid_list])
        -- billlog({
        --     op="create_uid",
        --     curr_uid = uid_list[#uid_list]
        -- })
        return uid_list
    end

    return false
end

--通过account_id 取 uid
function guid_mgr:query_uid(guid)
    if guid and type(guid) == 'number' then
        local conn = self.redis_pool:get_conn_from_pool()
        local guid_key = self:make_guid_key(guid)
        local uid = conn:get(guid_key)
        if not uid then
            mongo_data = self:select_from_mongodb_guid(guid)
            if mongo_data then
                uid = mongo_data.uid
                self:save_data_to_cache(guid,uid,conn)
            end
        end

        self.redis_pool:putback_to_pool(conn)
        if uid then
            return tonumber(uid) 
        end
    end

    return false
end

--通过uid 取 account_id
function guid_mgr:query_guid(uid)
    if uid and type(uid) == 'number' then
        local conn = self.redis_pool:get_conn_from_pool()
        local uid_key = self:make_uid_key(uid)
        local guid = conn:get(uid_key)
        if not guid then
            mongo_data = self:select_from_mongodb_uid(uid)
            if mongo_data then
                guid = mongo_data.guid
                self:save_data_to_cache(guid,uid,conn)
            end
        end

        self.redis_pool:putback_to_pool(conn)
        if guid then
            return tonumber(guid) 
        end
    end

    return false
end

return guid_mgr
